package org.study.javafx.study01.tree.code;

import cn.hutool.core.io.resource.ClassPathResource;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import lombok.extern.slf4j.Slf4j;
import org.study.javafx.study01.AppStarter;
import org.study.javafx.study01.config.AppConfig;

import java.util.Arrays;
import java.util.List;

/**
 * 参考 https://blog.csdn.net/zy103118/article/details/122573538
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2024年08月18日
 */
@Slf4j
public class TreeCode1_3 extends Application {
    /**
     * 直接运行此方法会报如下错误：
     * 错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序
     * 请运行 {@link AppStarter#main(String[])}
     */
    public static void main(String[] args) {
        AppConfig.init();
        launch(args);
    }

    /**
     * 创建一个图片节点类型对象
     */
    private final Node rootIcon = new ImageView(new Image(new ClassPathResource("icon/icon.png").getPath()));
    private final Node deptIcon = new ImageView(new Image(new ClassPathResource("icon/icon.png").getPath()));
    /**
     * 创建员工信息数据集合
     */
    List<Employee> employees = Arrays.asList(
            new Employee("Jacob Smith", "Accounts Department"),
            new Employee("Isabella Johnson", "Accounts Department"),
            new Employee("Ethan Williams", "Sales Department"),
            new Employee("Emma Jones", "Sales Department"),
            new Employee("Michael Brown", "Sales Department"),
            new Employee("Anna Black", "Sales Department"),
            new Employee("Rodger York", "Sales Department"),
            new Employee("Susan Collins", "Sales Department"),
            new Employee("Mike Graham", "IT Support"),
            new Employee("Judy Mayer", "IT Support"),
            new Employee("Gregory Smith", "IT Support")
    );
    /**
     * 根节点选项元素
     */
    TreeItem<String> rootNode;

    @Override
    public void init() throws Exception {
        super.init();
        // 创建根节点选项元素对象
        this.rootNode = new TreeItem<>("根节点元素", rootIcon);
    }

    @Override
    public void start(Stage stage) throws Exception {
        // 设置根节点元素初始化展开
        rootNode.setExpanded(true);
        for (Employee employee : employees) {
            // 创建员工节点选项对象
            TreeItem<String> empLeaf = new TreeItem<>(employee.getName());
            boolean found = false;
            for (TreeItem<String> depNode : rootNode.getChildren()) {
                // 对应部门元素对象上添加对应员工的节点
                if (depNode.getValue().contentEquals(employee.getDepartment())) {
                    depNode.getChildren().add(empLeaf);
                    found = true;
                    break;
                }
            }
            if (!found) {
                // 创建新部门节点选项对象
                TreeItem<String> depNode = new TreeItem<>(employee.getDepartment(), deptIcon);
                // 根节点对象上添加部门节点对象
                rootNode.getChildren().add(depNode);
                // 部门节点
                depNode.getChildren().add(empLeaf);
            }
        }
        stage.setTitle("TreeView更新节点测试");
        // 创建垂直盒子布局器
        VBox box = new VBox();
        // 创建一个场景对象
        final Scene scene = new Scene(box, 500, 300);
        // 设置场景背景颜色
        scene.setFill(Color.LIGHTGRAY);
        // 创建一个树形结构根节点
        TreeView<String> treeView = new TreeView<>(rootNode);
        // 将树形结构对象设置为可编辑
        treeView.setEditable(true);
        treeView.setCellFactory((TreeView<String> p) -> new TextFieldTreeCellImpl());
        box.getChildren().add(treeView);
        stage.setScene(scene);
        stage.show();
    }

    @Override
    public void stop() throws Exception {
        super.stop();
    }

    private static final class TextFieldTreeCellImpl extends TreeCell<String> {
        /**
         * 文本域对象的定义
         */
        private TextField textField;

        /**
         * 编辑时机的时候的回调函数
         */
        @Override
        public void startEdit() {
            // 调用父类的开始编辑模板方法
            super.startEdit();
            if (textField == null) {
                // 创建文本域对象
                createTextField();
            }
            // 设置文本内容
            setText(null);
            // 设置图形外观为前文定义的textField对象
            setGraphic(textField);
            // 选中文本域对象使其获得焦点
            textField.selectAll();
        }

        @Override
        public void cancelEdit() {
            // 取消编辑内容文本
            super.cancelEdit();
            // 设置文本内容为所选条目
            setText(getItem());
            // 设置去小时候的所选图形外观对象为树形结构所选的图形外观组件
            setGraphic(getTreeItem().getGraphic());
        }

        /**
         * 更新选项（重写继承自TreeCell类的模板方法）
         */
        @Override
        public void updateItem(String item, boolean empty) {
            // 更新树形结构选项，调用父类的模板方法
            super.updateItem(item, empty);
            if (empty) {
                // 设置文本元素为空
                setText(null);
                // 设置图形元素为空
                setGraphic(null);
            } else {
                if (isEditing()) {
                    // 如果正在编辑
                    if (textField != null) {
                        // 将前文定义的文本域内容设置为从编辑的cell组件中获取的文本内容
                        textField.setText(getString());
                    }
                    // 设置文本内容为null
                    setText(null);
                    // 设置图形外观为前文定义的textField类型元素对象
                    setGraphic(textField);
                } else {
                    // 设置文本内容
                    setText(getString());
                    // 设置外观图形组件为所选树形结构中的图形外观元素
                    setGraphic(getTreeItem().getGraphic());
                }
            }
        }

        /**
         * 创建文本域对象
         */
        private void createTextField() {
            // 创建文本域，初始化文本域对象的文本内容为从cell组件中取文本值
            textField = new TextField(getString());
            // 针对本文本域对象的键盘释放时间处理回调函数的编写
            textField.setOnKeyReleased((KeyEvent t) -> {
                // 判断当前敲击的键如果是回车键
                if (t.getCode() == KeyCode.ENTER) {
                    // 则调用继承自父类TreeCell类型的提交编辑改变内容方法
                    commitEdit(textField.getText());
                } else if (t.getCode() == KeyCode.ESCAPE) {
                    // 判断当前键盘事件中获取当前使用键盘的代码是否是ESC键
                    // 调用取消编辑方法
                    cancelEdit();
                }
            });
        }

        private String getString() {
            // 获取文本选项域对象的内容,利用继承自Cell父类的getItem()选项方法获取
            return getItem() == null ? "" : getItem();
        }
    }

    static class Employee {
        /**
         * mvvm机制下的和String很像的数据类型SimpleStringProperty
         */
        private final SimpleStringProperty name;
        private final SimpleStringProperty department;

        /**
         * mvvm机制下的和String很像的数据类型SimpleStringProperty
         */
        private Employee(String name, String department) {
            this.name = new SimpleStringProperty(name);
            this.department = new SimpleStringProperty(department);
        }

        public String getName() {
            return name.get();
        }

        public void setName(String fName) {
            name.set(fName);
        }

        public String getDepartment() {
            return department.get();
        }

        public void setDepartment(String fName) {
            department.set(fName);
        }
    }
}
